﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.SecurityControl;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;

namespace Wyn.PMS.Common.NightAudit
{
    public class CacheContainer
    {
        private IDictionary<string, DateTime> _cache = new Dictionary<string, DateTime>();

        private static volatile CacheContainer _instance;

        private static readonly object _lock = new object();

        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        private DateTime _versionTimeStamp = DateTime.Parse("1984/11/09 18:00:00 PM");

        private static readonly ReaderWriterLockSlim barrier = new ReaderWriterLockSlim();
       
        private CacheContainer()
        {
        }

        public static CacheContainer GetInstance()
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        var cc = new CacheContainer();

                        cc.InitCache();

                        _instance = cc;

                        Thread.MemoryBarrier();
                    }
                }
            }
            return _instance;
        }

        private void InitCache()
        {
            ICacheCenterRepository ccRepository = container.Resolve<ICacheCenterRepository>();

            try
            {
                Expression<Func<CacheCenter, bool>> exp = c => c.IsValid == true;

                IList<CacheCenter> caches=null;

                var transactionOptions = new System.Transactions.TransactionOptions();
                
                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
               
                using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    caches = ccRepository.BatchFind(GlobalConst.ROOT_HOTEL_ID, exp);
                    
                    scope.Complete();
                }

                if (caches != null && caches.Any()) FillCache(caches);

            }catch (Exception error)
            {
                OperateLog.ErrorLog(DateTime.Now + "中央缓存初始化失败" + error);
            }
        }

        public void RefreshCache(DateTime? time)
        {
            try
            {
                ICacheCenterRepository ccRepository = container.Resolve<ICacheCenterRepository>();

                DateTime versionTime = time ?? _versionTimeStamp;
            
                Expression<Func<CacheCenter, bool>> exp = c => c.UpdateDate > versionTime;

                IList<CacheCenter> caches = null;

                var transactionOptions = new System.Transactions.TransactionOptions();

                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

                using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    caches = ccRepository.BatchFind(GlobalConst.ROOT_HOTEL_ID, exp);

                    scope.Complete();
                }

                if (caches != null && caches.Any()) FillCache(caches);

            }
            catch (Exception error)
            {
                OperateLog.ErrorLog(DateTime.Now + "中央缓存刷新失败" + error);
            }

        }

        private void FillCache(IList<CacheCenter> caches)
        {
            _versionTimeStamp = caches.Max(r => r.UpdateDate);

            barrier.EnterUpgradeableReadLock();

            foreach (var cache in caches)
            {
                try
                {
                    barrier.EnterWriteLock();

                    if (_cache.ContainsKey(cache.CacheName))
                    {
                        _cache.Remove(cache.CacheName);
                    }
                    if (cache.IsValid)
                    {
                        UpdateCache(cache.CacheName);

                        _cache.Add(cache.CacheName, cache.UpdateDate);
                    }
                }finally
                {
                    barrier.ExitWriteLock();
                }
            }
            barrier.ExitUpgradeableReadLock();
        }

        private void UpdateCache(string cacheName)
        {
            switch(cacheName)
            {
                case CenterCacheClass.PRICE_CACHE:
                    PriceCache pc = PriceCache.GetInstance();
                    pc.UpdatePriceCache();
                    break;
                case CenterCacheClass.RATE_CODE_CACHE:
                    PriceCache pcRate = PriceCache.GetInstance();
                    pcRate.UpdateRateCache();
                    break;
                case CenterCacheClass.BIZ_DAY_CACHE:
                    BizDayCache bc = BizDayCache.GetInstance();
                    bc.RefreshCache();
                    break;
            }
        }

    }
}
